#ifndef CAMERA_H
#define CAMERA_H

#include <QVector3D>
#include <QMatrix4x4>

class QTimer;

struct CameraInfo
{
    bool valid{ false }; ///< 是否为有效数据
    //    bool is_changed_{ false }; ///< 相机数据是否变化

    QMatrix4x4 view_matrix;                   ///< 视图矩阵
    QVector3D view_position{ 0.0, 0.0, 0.0 }; ///< 相机位置

    QVector3D rotate_angle{ 0.0, 0.0, 0.0 }; ///< 旋转角度

    QMatrix4x4 projection_matrix; ///< 投影矩阵
    QMatrix4x4 gravity_matrix;    ///< 重力矩阵

    QVector3D distance; ///< 相机位置到目标点的距离向量

    QVector3D camera_eye;  ///< 摄像机在世界坐标系中的位置
    QVector3D camera_look; ///< 摄像机正在观察的目标方向
    QVector3D camera_up;   ///< 摄像机在观察目标时的上方方向

    QVector3D forward; ///< 向前单位向量
    QVector3D right;   ///< 向右单位向量
    QVector3D up;      ///< 向上单位向量
};

class Camera : public QObject
{
    Q_OBJECT

    /// 按键操控
    enum KeyStatus
    {
        KeyStatus_No = 0x00,        ///< 不动
        KeyStatus_Up = 0x01,        ///< 向上 Space - 鼠标右键上移
        KeyStatus_Down = 0x02,      ///< 向下 Ctrl  - 鼠标右键下移
        KeyStatus_Left = 0x04,      ///< 向左 A     - 鼠标右键左移
        KeyStatus_Right = 0x08,     ///< 向右 D     - 鼠标右键右移
        KeyStatus_Forword = 0x10,   ///< 前进 W     - 鼠标滚轮上滑
        KeyStatus_Back = 0x020,     ///< 后退 S     - 鼠标滚轮下滑
        KeyStatus_TurnLeft = 0x40,  ///< 左转 Q     - 鼠标左键左移
        KeyStatus_TurnRight = 0x80, ///< 右转 E     - 鼠标左键右移
    };

public:
    Camera(QObject *parent = nullptr);
    Camera(const Camera &camera);

    /// 安装渲染窗口
    void installRenderForm(QWidget *render_form);

    /// 相机设置
    void setCamera(const QVector3D &eye, const QVector3D &look,
                   const QVector3D &up);

    /// 旋转使能
    void setRotateEnable(QVector3D rotate_enable);
    void setRotateEnableX(bool enable);
    void setRotateEnableY(bool enable);
    void setRotateEnableZ(bool enable);

    /// 视角矩阵
    QMatrix4x4 getViewMatrix() const;
    QVector3D getViewPosition() const;

    /// 视图坐标系旋转角度
    QVector3D getRotateAngle() const;
    void rotate(float angle, const QVector3D &axis);
    void rotate(float angle_x, float angle_y, float angle_z);
    inline void rotateX(float angle) { rotate(angle, { 1.0, 0.0, 0.0 }); }
    inline void rotateY(float angle) { rotate(angle, { 0.0, 1.0, 0.0 }); }
    inline void rotateZ(float angle) { rotate(angle, { 0.0, 0.0, 1.0 }); }

    /// 平移 x,y 移动
    void translate(float x, float y, float z);
    inline void translate(const QVector3D &translation)
    {
        translate(translation.x(), translation.y(), translation.z());
    }

    /// 缩放 z 移动
    inline void scale(float factor) { translate({ 0.0, 0.0, factor }); };

    /// 设置鼠标滚轮缩放系数
    void setMouseScaleFactor(float scale_factor);

    /**
     * @brief setProjectionMatrix: 设置投影矩阵
     * @param vertical_angle: 视野的垂直角度，也称为垂直视角，
     * 表示从相机视角的中心向上和向下延伸的角度范围
     * @param aspect_ratio: 视口的宽高比，通常为视口的宽度除以高度
     * @param near_plane: 相机的近裁剪面的距离，即相机能够看到的最近的距离
     * @param far_plane: 相机的远裁剪面的距离，即相机能够看到的最远的距离
     */
    void setProjectionMatrix(float vertical_angle, float aspect_ratio,
                             float near_plane, float far_plane);
    QMatrix4x4 getProjectionMatrix() const;

    /// 重力矩阵
    QMatrix4x4 getGravityMatrix() const;

    /**
     * @brief setGravityComponent 根据重力分量计算重力矩阵
     * @param gravity_matrix 重力在 x, y, z 三个方向的分量
     */
    void setGravityComponent(const QVector3D &gravity_matrix);

    /**
     * @brief getDist：计算相机位置到目标点的距离向量。
     *
     * 将相机位置向量 camera_eye_ 投影到相机坐标系的三个单位向量上
     * (right_, up_, forward_)， 从而得到相机位置到目标点的距离向量。
     * 这样的计算可以用来确定相机在相机坐标系中的位置，从而实现相机的移动和旋转。
     *
     * @return 相机位置到目标点的距离向量
     *
     *
     */
    QVector3D getDistance();

    CameraInfo getInfo();

protected:
    virtual bool eventFilter(QObject *watched, QEvent *event) override;

private:
    void initCamera();
    double normalizeAngle(double angle);
    QMatrix4x4 adjoint(const QMatrix4x4 &mat);

    /// 更新相机矩阵
    void updateViewMatrix();

    /// 将鼠标置于窗口中心
    void centerMouseInWidget();

private Q_SLOTS:
    void updateKeyStatus();

private:
    QWidget *render_form_{ nullptr };
    QPoint last_mouse_pos_;
    int key_status_{ KeyStatus_No };
    QTimer *timer_update_{ nullptr };

    QVector3D camera_eye_;  ///< 摄像机在世界坐标系中的位置
    QVector3D camera_look_; ///< 摄像机正在观察的目标方向
    QVector3D camera_up_;   ///< 摄像机在观察目标时的上方方向

    QVector3D forward_; ///< 向前单位向量
    QVector3D right_;   ///< 向右单位向量
    QVector3D up_;      ///< 向上单位向量

    /// 重力矩阵未设置时的摄像机参数
    QVector3D original_camera_eye_;
    QVector3D original_camera_look_;
    QVector3D original_camera_up_;

    QMatrix4x4 view_matrix_;       ///< 视图矩阵
    QMatrix4x4 gravity_matrix_;    ///< 重力矩阵
    QMatrix4x4 projection_matrix_; ///< 透视投影矩阵

    /// 视图坐标系旋转角度 [-360, 360]
    QVector3D rotate_angle_{ 0, 0, 0 };
    /// 旋转使能
    QVector3D rotate_enable_{ true, true, true };

    /// 鼠标滚轮缩放系数
    float mouse_scale_factor_{ 1.0 };

    bool is_changed_{ false };
};

#endif // CAMERA_H
